#include "stack.h"

pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;

void push (Stack *stk, char *str) {
	Node *node = (Node *)malloc(sizeof(Node));
	node->str = (char *)malloc(sizeof(char)*(strlen(str) + 1));
	strcpy(node->str, str);
	pthread_mutex_lock( &mutex1 );
	if (stk->head == NULL) {
		node->next = NULL;
	} else {
		node->next = stk->head;
	}
	stk->head = node;
	pthread_mutex_unlock( &mutex1 );
}

void pop (Stack *stk) {
	Node *tmp;
	pthread_mutex_lock( &mutex1 );
	if (stk->head != NULL) {
		tmp = stk->head->next;
		free(stk->head->str);
		free(stk->head);
		stk->head = tmp;
	}
	pthread_mutex_unlock( &mutex1 );
}

void top (Stack *stk) {
	pthread_mutex_lock( &mutex1 );
	if (stk->head != NULL) {
		fprintf(stdout, "OUTPUT: %s", stk->head->str);
	} else {
		fprintf(stdout, "DEBUG: stack is empty");
	}
	pthread_mutex_unlock( &mutex1 );
}

void freeStack(Stack *stk) {
	Node *tmp;
	while (stk->head != NULL) {
		tmp = stk->head->next;
		free(stk->head->str);
		free(stk->head);
		if (tmp == NULL) {
			break;
		} else {
			stk->head = tmp;
		}
	}
	stk = NULL;
}

char *getUserInput() {
	char *input = (char*)malloc(sizeof(char)*DEFAULT_USER_INPUT_LENGTH);
	if (NULL==input) {
		fprintf(stdout, "Error: allocation failed");
		return NULL;
	}
	if (fgets(input, DEFAULT_USER_INPUT_LENGTH, stdin) == NULL) {
		fprintf(stdout, "Error: EOF or IO error occured");
		free(input);
		return NULL;
	}
	return input;
}

int execFunc(char *input, Stack *stk){
	char *func;
	int end = 0, i, begin;
	/* find the end of the command */
	while (input[end] != '\n' && input[end] != '\0' && input[end] != '\t' && input[end] != ' ') {
		end++;
	}
	/* create a string out of the command */
	func = (char *)malloc(sizeof(char)*(end + 1));
	for (i = 0; i < end; i++) {
		func[i] = input[i];
	}
	func[i] = '\0';
	if (strcmp(func, (char *) "POP") == 0) {
		pop(stk);
	}
	else if (strcmp(func, (char *) "TOP") == 0) {
		top(stk);
	}
	else if (strcmp(func, (char *) "PUSH") == 0) {
		/* jump over white spaces to get to the string */
		while ((input[end] != '\n' || input[end] != '\0') && (input[end] == '\t' || input[end] == ' ')) {
		end++;
		}
		if	(input[--end] == '\0' || input[end] == '\n') {	
			fprintf(stdout, "Error: no string to push into stack");
		} else {
			/* find the beginning and end of the string */
			begin = ++end;
			while (input[end] != '\n' && input[end] != '\0') {
				end++;
			}
			if (input[end] != '\n') {
				fprintf (stdout, "Error: the input is not null terminated");
			} else {
				push(stk, &(input[begin]));
			}
		}
	} else if (strcmp(func, (char *) "QUIT") == 0) {
		free(func);
		return 0;
	} else {
		fprintf(stdout, "Error: invalid command");
	}
	free(func);
	return 1;
}

Stack *createStack() {
	Stack *stk = (Stack *)malloc(sizeof(Stack));
	stk->head = NULL;
	return stk;
}

int main() {
	char *input;
	int cont = 1;
	Stack *stk = (Stack *)malloc(sizeof(Stack));
	stk->head = NULL;
	while (cont) {
		input = getUserInput();
		if (input != NULL) {
			cont = execFunc(input, stk);
			free(input);
		}
	}
	freeStack(stk);
}

/*pthread_cond_t  condition_cond  = PTHREAD_COND_INITIALIZER;

typedef struct ts_struct {
	bool flag;
} Ts_object;

Bool test_set (Ts_object  *ts) {
    if (ts->flag == FALSE) {
        ts->flag = TRUE; 
        return FALSE; 
    }
	else return TRUE;
}

void reset (Ts_object *ts) {
	ts->flag = FALSE;
}

void lock_mutex (mutex * m) {
	while (test_set(Ts_object *) m) {
		sleep((unsigned int) 2);
	}
}

void unlock_mutex(mutex *m) {
	reset((Ts_object *) m)
}*/
